//
//  MultithreadingViewController.swift
//  YUANSHI
//
//  Created by pro on 2020/1/13.
//  Copyright © 2020 wangbin. All rights reserved.
//

import UIKit

class MultithreadingViewController: WBBaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "多线程"
//        print(Thread.main)
        
//         Thread（最轻，灵活度高）
//        threadQueueLenarn()
        
        //GCD Grand Central Dispatch（调度队列+操作对象）
//        gcdThreadQueueLenarn()
        
//        Operation 的使用
//        operationLearn()
    }
    
    func operationLearn() {
        
//        第一步：创建Operation
        let op = Operation.init()
//        第二步：把要执行的代码放入operation中
        op.completionBlock = {
            print(#function,#line,Thread.current)
        }
//        第三步：创建OperationQueue
        let opQueue = OperationQueue.init()
//        opQueue.maxConcurrentOperationCount = 3  设置线程最大并发数
//        第四步：把Operation加入到线程中
//        opQueue.addOperation(op)
        
        opQueue.addOperation {
            print(#function,#line,Thread.current)
        }
        
        //使用BlockOperation创建operation
//        let operation = BlockOperation.init {
            //打印，看看在哪个线程中

//            print(#function,#line,Thread.current)
//        }
//       operationQueue.maxConcurrentOperationCount = 3
        //直接运行operation，看看运行在哪个线程中
//        operation.start()
   //创建完Operation如果直接运行，就会在当前线程执行。也就是说，如果实在主线程创建并且start的，那就会在主线程执行；如果是在子线程创建并且start的，那就会在子线程执行
    }
    
    
    func gcdThreadQueueLenarn() {
        
        //gcd基础
//        GCDBasics()
        
        //延时执行
//        AftenrEven()
        
        
        //        多个任务全部结束后做一个全部结束的处理
                multitaskEven()
        
        //9，concurrentPerform 指定次数的Block最加到队列中//DispatchQueue.concurrentPerform函数是sync函数和DispatchGroup的关联API。按指定的次数将指定的Block追加到指定的DispatchQueue中，并等待全部处理执行结束。//因为concurrentPerform函数也与sync函数一样，会等待处理结束，因此推荐在async函数中异步执行concurrentPerform函数。concurrentPerform函数可以实现高性能的循环迭代。
//        concurrentPerform()
        
//        10，信号，信号量
//        DispatchSemaphore(value: )：用于创建信号量，可以指定初始化信号量计数值，这里我们默认1.
//        semaphore.wait()：会判断信号量，如果为1，则往下执行。如果是0，则等待。
//        semaphore.signal()：代表运行结束，信号量加1，有等待的任务这个时候才会继续执行。
//        semaphoreEven()
    }
    
    func semaphoreEven() {
//        let queue = DispatchQueue(label: "labelname", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit)
        let queue = DispatchQueue.global(qos: .default)
//        for i in 1...10 {
//            queue.async {
//                print("\(i)")
//            }
//        }
        //使用信号量保证正确性
        //创建一个初始计数值为1的信号
        let semaphore = DispatchSemaphore(value: 1)
        for i in 1...15{
            queue.async {
                //永久等待，直到Dispatch Semaphore的计数值 >= 1
                semaphore.wait()
                print(i)
                //发信号，使原来的信号计数值+1
                sleep(1)
                semaphore.signal()
            }
        }
        
        
    }
    
    func concurrentPerform() {
        let queue = DispatchQueue.global(qos: .default)
        
        queue.async {
            //通过concurrentPerform，循环变量数组
            DispatchQueue.concurrentPerform(iterations: 6) {(index) -> Void in
                print(index)
            }
             
            //执行完毕，主线程更新
            DispatchQueue.main.async {
                print("done")
            }
        }
    }
    
    
    //GCD多任务
    func multitaskEven() {
//        let group = DispatchGroup()
//        group.enter()
//        self.sendHTTPRequest1(params:[String: Any]) {
//            print("request complete")
//            group.leave()
//        }
//        group.enter()
//        self.sendHTTPRequest1(params:[String: Any]) {
//            print("request complete")
//            group.leave()
//        }
//        group.notify(queue: DispatchQueue.main) {
//            print("all requests come back")
//        }
        //        async(group:)：用来监视一组block对象的完成，你可以同步或异步地监视
        //        notify()：用来汇总结果，所有任务结束汇总，不阻塞当前线程
        //        wait()：等待直到所有任务执行结束，中途不能取消，阻塞当前线程
        //获取系统存在的全局队列
        let queue = DispatchQueue.global(qos: .default)
        
        //定义一个group
        let group = DispatchGroup.init()
        
        //并发任务，顺序执行
        
        queue.async(group: group){
            sleep(2)
            print("1")
        }
        queue.async(group: group){
            sleep(5)
            print("2")
        }
        queue.async(group: group){
            sleep(2)
            print("3")
        }
        
        //1,所有任务执行结束汇总，不阻塞当前线程
        group.notify(queue: queue) {
            print(Thread.current)
            print("任务完成")
            DispatchQueue.main.async {
                print(Thread.current)
            }
        }
        
        //2,永久等待，直到所有任务执行结束，中途不能取消，阻塞当前线程
//        group.wait()
        print("任务全部执行完成")
    }
    
    func AftenrEven() {
        //延时2秒执行
        //asyncAfter并不是在指定时间后执行任务处理，而是在指定时间后把任务追加到queue里面。因此会有少许延迟。注意，我们不能（直接）取消我们已经提交到 asyncAfter 里的代码
        //        DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + 2.0) {
        //            print("after!")
        //        }
        //        DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: DispatchTime.now() + 2) {
        //            print("after1!")
        //        }
        //如果需要取消正在等待执行的Block操作，我们可以先将这个Block封装到DispatchWorkItem对象中，然后对其发送cancle，来取消一个正在等待执行的block。
        //将要执行的操作封装到DispatchWorkItem中
        let task = DispatchWorkItem { print("after!") }
        //延时2秒执行
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task)
        //取消任务
        task.cancel()
        
    }
    
    func GCDBasics() {
        //创建串行队列（1）自己创建一个队列
        //        第一个参数代表队列的名称，可以任意起名
        //        第二个参数代表队列属于串行还是并行执行任务
        //        串行队列一次只执行一个任务。一般用于按顺序同步访问，但我们可以创建任意数量的串行队列，各个串行队列之间是并发的。
        //        并行队列的执行顺序与其加入队列的顺序相同。可以并发执行多个任务，但是执行完成的顺序是随机的。
        let serial = DispatchQueue(label: "serialQueue1")
        //创建并行队列
        let concurrent = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
        
        //                获取全局队列
        //                Global Dispatch Queue有4个执行优先级：
        //                .userInitiated  高
        //                .default  正常
        //                .utility  低
        //                .background 非常低的优先级（这个优先级只用于不太关心完成时间的真正的后台任务）
        let globalQueue = DispatchQueue.global(qos: .default)
        //                获取主线程队列
        let mianQueue = DispatchQueue.main
        //                一步执行
        DispatchQueue.global(qos: .default).async {
            //处理耗时的代码块
            print("do work")
            //处理完成后可以调用主队列刷新界面
            DispatchQueue.main.async {
                print("main refresh")
            }
        }
        
        //添加同步代码块到global队列
        //不会造成死锁，但会一直等待代码块执行完毕
        //        DispatchQueue.global(qos: .default).sync {
        //            print("sync1")
        //        }
        //        print("end1")
        //添加同步代码块到main队列
        //会引起死锁
        //因为在主线程里面添加一个任务，因为是同步，所以要等添加的任务执行完毕后才能继续走下去。但是新添加的任务排在
        //队列的末尾，要执行完成必须等前面的任务执行完成，由此又回到了第一步，程序卡死
        //                DispatchQueue.main.sync {
        //                    print("sync2")
        //                }
        //                print("end2")
        
        let conQueue = DispatchQueue.init(label: "concurrentQueue1", attributes: .concurrent)
        conQueue.suspend()//暂停队列
        conQueue.resume()//继续队列
    }
    
    
    
    
   
}

//THREAD线程
extension MultithreadingViewController{
    
     func threadQueueLenarn() {
            //类方法创建线程第一种方式（无需手动开启，会自动执行）
            //        Thread.detachNewThread {
            //            print(Thread.current)
            //        }
            //        print(Thread.threadPriority)
            //类方法创建线程第二种方式（无需手动开启，会自动执行）
            //        Thread.detachNewThreadSelector(#selector(newThread), toTarget: self, with: nil)
            
            //        实例方法创建线程的方式一（需要手动启动线程）
            let thread1 = Thread.init {
                
                print(Thread.current)
                Thread.sleep(forTimeInterval: 4)
                print("thread1沉睡了4秒")
    //            Thread.exit()
            }
            thread1.name = "线程1"
            thread1.threadPriority = 0.1
            //手动启动
            thread1.start()
            
            let thread2 = Thread.init(target: self, selector: #selector(newThread), object: nil)
              //设置优先级 数值越大优先级别越高
            thread2.threadPriority = 0.6
            thread2.name = "线程2" //设置线程名称
    //        thread2.qualityOfService = QualityOfService.userInteractive //设置线程优先级系统提供的枚举类型
            thread2.start()
    //        let _ = Thread.current //获取当前线程
    //        let _ = Thread.main //获取主线程
    //        let _ = Thread.isMainThread //判断是否为主线程
    //        let _ = Thread.threadPriority //判断线程的优先等级 数值越大优先级别越高 默认值0.5
    //        print(thread2.threadPriority)
    //        print(thread2.isFinished) //线程是否结束
    //        print(thread2.isCancelled) //线程是否取消
    //        print(thread2.isExecuting) //线程是否正在执行

        }
        
        @objc func newThread(){
            print(Thread.isMainThread )
            print(Thread.current)
            print(Thread.threadPriority())//        print(Thread.isFinished)
            Thread.sleep(forTimeInterval: 4) //线程睡眠
    //        print(Thread.)
            print("沉睡了4秒")
    //        Thread.exit() //退出当前线程
           
        }
    
    
}
